package com.itheima.balance;

import com.itheima.weight.WeightMeta;
import com.itheima.weight.WeightRandomUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.reactive.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.reactive.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.reactive.Request;
import org.springframework.cloud.client.loadbalancer.reactive.Response;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.http.HttpHeaders;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: springcloud
 * @description: 实现不同的选择实例的策略
 * @author: zhanghz001
 * @create: 2021-08-02 15:51
 **/
public class ZhzGrayLoadBalancer implements ReactorServiceInstanceLoadBalancer {
    private static final Log log = LogFactory.getLog(ZhzGrayLoadBalancer.class);
    
    //服务的列表
    private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
    
    //服务id号,
    private String serviceId;
    
    public ZhzGrayLoadBalancer(
            ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider,
            String serviceId) {
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
        this.serviceId = serviceId;
    }
    
    /**
     * 根据策略选择不同的实例
     * 比如这里按照权重筛选
     *
     * @param request 用户请求信息封装对象
     * @return
     */
    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        //获取所有请求头
        HttpHeaders headers = (HttpHeaders) request.getContext();
        
        //服务列表为空
        if (this.serviceInstanceListSupplierProvider != null) {
            //获取有效的实例对象
            ServiceInstanceListSupplier supplier =
                    this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
            //获取有效实例集合
            Mono<List<ServiceInstance>> next = supplier.get().next();
            //按照指定路由规则,查询符合的实例对象
            return supplier.get().next().map(list -> getInstanceResponse(list, headers));
        }
        return null;
    }
    
    /**
     * 获取实例
     *
     * @param instances
     * @param headers
     * @return
     */
    public Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances, HttpHeaders headers) {
        //找不到实例
        if (instances.isEmpty()) {
            return new EmptyResponse();
        } else {
            //获取版本号
            String versionNo = headers.getFirst("version");
            
            // 
            //版本号或权重路由
            return StringUtils.isEmpty(versionNo) ?
                    weight(instances) : version(instances, versionNo);
        }
    }
    
    /******
     * 权重选择一个实例
     * @return
     */
    public Response<ServiceInstance> weight(List<ServiceInstance> instances) {
        //weightMap 实例,权重
        HashMap<ServiceInstance, Integer> weightMap = new HashMap<>();
        
        for (ServiceInstance instance : instances) {
            //获取元数据中的权重
            Map<String, String> metadata = instance.getMetadata();
            Integer serviceWeight = Double.valueOf(metadata.get("nacos.weight")).intValue();
            //存入weightMap中
            weightMap.put(instance, serviceWeight);
        }
        
        //将服务权重map对象,封装成weightMeta对象
        WeightMeta<ServiceInstance> weightMeta = WeightRandomUtils.buildWeightMeta(weightMap);
        //随机选择一个服务
        ServiceInstance serviceInstance = weightMeta.random();
        return serviceInstance == null ? new EmptyResponse() : new DefaultResponse(serviceInstance);
    }
    
    /***
     * 版本号选择
     */
    public Response<ServiceInstance> version(
            List<ServiceInstance> instances, String version) {
        //存储所有有效服务
        List<ServiceInstance> serviceInstances = new ArrayList<>();
        
        //循环所有服务
        for (ServiceInstance instance : instances) {
            //对比元数据中是否包含版本号信息
            Map<String, String> metadata = instance.getMetadata();
            
            for (Map.Entry<String, String> entry : metadata.entrySet()) {
                String key = entry.getKey();
                String value = entry.getValue();
                if ("version".equals(key) && value.equals(version)) {
                    serviceInstances.add(instance);
                }
            }
        }
        //根据权重选择
        return weight(serviceInstances);
    }
}
